package com.symaster.gameengine.test;

import cn.hutool.core.io.IoUtil;
import org.lwjgl.Version;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryStack;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.Channels;

import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.NULL;

public class FBOExample {

    private long window;
    private int fbo;
    private int fboTexture;

    public static void main(String[] args) {
        new FBOExample().run();
    }

    private static ByteBuffer getByteBuffer(InputStream inputStream) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
            IoUtil.copy(inputStream, outputStream);
            return ByteBuffer.wrap(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static ByteBuffer readImageToByteBuffer(InputStream inputStream) throws IOException {
        // 读取 InputStream 到 ByteBuffer
        try (var channel = Channels.newChannel(inputStream)) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); // 预先分配一个 16KB 的缓冲区
            int bytesRead;
            while ((bytesRead = channel.read(buffer)) != -1) {
                if (buffer.remaining() == 0) {
                    // 如果缓冲区已满，扩展缓冲区大小
                    ByteBuffer newBuffer = ByteBuffer.allocateDirect(buffer.capacity() * 2);
                    buffer.flip();
                    newBuffer.put(buffer);
                    buffer = newBuffer;
                }
            }
            buffer.flip();
            return buffer;
        }
    }

    public void run() {
        System.out.println("LWJGL Version " + Version.getVersion() + "!");

        init();
        loop();

        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);

        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private void init() {
        GLFWErrorCallback.createPrint(System.err).set();

        if (!glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

        window = glfwCreateWindow(800, 600, "FBO Example", NULL, NULL);
        if (window == NULL) {
            throw new RuntimeException("Failed to create the GLFW window");
        }

        glfwMakeContextCurrent(window);
        glfwSwapInterval(1);
        glfwShowWindow(window);

        GL.createCapabilities();

        // 初始化 FBO
        setupFBO();
    }

    private void setupFBO() {
        // 创建 FBO
        fbo = glGenFramebuffers();
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);

        // 创建纹理，用作 FBO 的颜色附件
        fboTexture = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, fboTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null);

        // 设置纹理参数
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // 附加纹理到 FBO
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTexture, 0);

        // 检查 FBO 完整性
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            throw new RuntimeException("Framebuffer is not complete!");
        }

        // 解除绑定 FBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    private void loop() {
        // 设置背景色
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        // 加载图片并生成纹理
        int textureID = loadTexture("C:\\Users\\18790\\Pictures\\3767cb5b-02da-4b3e-9895-1371ab73283c.jpg");

        boolean init = false;

        while (!glfwWindowShouldClose(window)) {

            if (!init) {
                // 渲染到 FBO
                glBindFramebuffer(GL_FRAMEBUFFER, fbo);
                glViewport(0, 0, 800, 600);  // 设置 FBO 视口大小

                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // 在 FBO 上绘制纹理

                glBindTexture(GL_TEXTURE_2D, textureID);
                glEnable(GL_TEXTURE_2D);
                renderQuad();
                glDisable(GL_TEXTURE_2D);

                init = true;
            }

            // 渲染到屏幕
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            glViewport(0, 0, 800, 600);  // 设置回窗口的视口大小

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            // 使用 FBO 纹理作为纹理绘制到屏幕
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, fboTexture);
            renderQuad();
            glDisable(GL_TEXTURE_2D);

            glfwSwapBuffers(window);
            glfwPollEvents();
        }


    }

    private void renderQuad() {
        // 绘制一个应用纹理的四边形
        glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex2f(-0.5f, -0.5f); // 左下角
        glTexCoord2f(1, 0);
        glVertex2f(0.5f, -0.5f); // 右下角
        glTexCoord2f(1, 1);
        glVertex2f(0.5f, 0.5f); // 右上角
        glTexCoord2f(0, 1);
        glVertex2f(-0.5f, 0.5f); // 左上角
        glEnd();
    }

    private int loadTexture(String filePath) {
        ByteBuffer image;
        int width;
        int height;

        try (MemoryStack stack = stackPush()) {
            IntBuffer w = stack.mallocInt(1);
            IntBuffer h = stack.mallocInt(1);
            IntBuffer channels = stack.mallocInt(1);

            ByteBuffer byteBuffer;
            try (FileInputStream inputStream = new FileInputStream(filePath);) {
                byteBuffer = readImageToByteBuffer(inputStream);
                // byteBuffer = getByteBuffer(inputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            image = STBImage.stbi_load_from_memory(byteBuffer, w, h, channels, 4);

            // image = STBImage.stbi_load(byteBuffer, w, h, channels, 4);

            if (image == null) {
                throw new RuntimeException("Failed to load a texture file: " + STBImage.stbi_failure_reason());
            }

            width = w.get();
            height = h.get();
        }

        int textureID = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, textureID);

        // 上传纹理数据
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

        // 设置纹理参数
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // 释放图像内存
        STBImage.stbi_image_free(image);

        return textureID;
    }
}
